﻿using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Actya.Web.Mvc;

namespace Actya.Web.Infrastructure
{
	/// <summary>
	/// Filter that injects the CMS toolbar into the output stream.
	/// </summary>
	/// <remarks>
	/// Idea and code thankfully borrowed from the Glimpse project: https://github.com/Glimpse and
	/// indirectly from Scott Mitchell: http://www.4guysfromrolla.com/articles/120308-1.aspx.
	/// </remarks>
	public class CmsToolbarFilter : MemoryStream
	{
		internal StringBuilder ResponseContent { get; set; }
		internal Stream OutputStream { get; set; }
		internal HttpContextBase HttpContext { get; set; }

		private readonly Regex _htmlEnd = new Regex("</html>", RegexOptions.Compiled | RegexOptions.Multiline);
		private readonly Regex _bodyEnd = new Regex("</body>", RegexOptions.Compiled | RegexOptions.Multiline);

		public CmsToolbarFilter(Stream output, HttpContextBase context)
		{
			ResponseContent = new StringBuilder();
			OutputStream = output;
			HttpContext = context;
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			// Convert the content in buffer to a string
			string contentInBuffer = Encoding.UTF8.GetString(buffer);

			// Buffer content in responseContent until we reach the end of the page's markup
			ResponseContent.Append(contentInBuffer);

			if (_htmlEnd.IsMatch(ResponseContent.ToString()))
			{
				// Fireup a second request that renders the toolbar and injects it just before the end body tag.
				var parentRequestContext = this.HttpContext.Request.RequestContext;
				var routeData = CreateToolbarRouteData(parentRequestContext.RouteData);
				var toolBarRequestContext = new RequestContext(this.HttpContext, routeData);
				var toolbarHandler = new MvcHandler(toolBarRequestContext);

				var html = "</body>";
				using (var stringWriter = new StringWriter(CultureInfo.CurrentCulture))
				{
					this.HttpContext.Server.Execute(HttpHandlerUtil.WrapForServerExecute(toolbarHandler), stringWriter, true);
					html = stringWriter + Environment.NewLine + html;
				}

				string content = _bodyEnd.Replace(ResponseContent.ToString(), html);
				
				// Write content to the outputStream
				byte[] outputBuffer = Encoding.UTF8.GetBytes(content);
				OutputStream.Write(outputBuffer, 0, outputBuffer.Length);
			}
		}

		private RouteData CreateToolbarRouteData(RouteData originalRouteData)
		{
			var routeData = new RouteData();
			routeData.Route = RouteTable.Routes[Constants.CmsAdminAreaRouteName];
			if (originalRouteData != null)
			{
				foreach (var routeValue in originalRouteData.Values)
				{
					routeData.Values.Add(routeValue.Key, routeValue.Value);
				}
				//foreach (var dataToken in originalRouteData.DataTokens)
				//{
				//    routeData.DataTokens.Add(dataToken.Key, dataToken.Value);
				//}
			}
			routeData.Values["controller"] = Constants.CmsToolbarControllerName;
			routeData.Values["action"] = Constants.CmsToolbarActionName;
			routeData.Values["theme"] = "Admin";
			return routeData;
		}
	}
}